/**************************************************************
*  Apple LLVM version 10.0.0 (clang-1000.10.43.1)             *
*  Copyright (C) 2021 Xuan-Yu-San 307100890@qq.com.           *
*                                                             *
*  This file is part of little-nginx.                         *
*  Little-NGINX is a castration version NGINX for learning    *
*  HTTP Message.                                              *
*                                                             *
*  @file     Server.h                                         *
*  @github   https://gitee.com/xuanyusan/little_nginx.git     *
*  @license  MIT License (MIT)                                *
**************************************************************/

#ifndef REQUEST_HPP
#define REQUEST_HPP

#include <string>
#include <iostream>
#include <sstream>
#include <map>

using namespace std;

class Request {
private:
    string request_str;
    string method;
    string path;
    string protocol;
    map<string, string> header_params;
    string body_content;
    friend ostream& operator<<(ostream&, Request&);
public:
    string getMethod() { return this->method; };
    string getPath() { return this->path; };
    Request(string);
    string json();
    string str();
    string get_request_url();
    void reset_request_str();
    bool match_path(string);
    void reset_path(string);
    void update_header_params(string, string);
    string get_header_params(string);
    ~Request();
};

void Request::reset_request_str() {
    string temp = "";
    temp += this->method + " " + this->path + " " + this->protocol + "\r\n";
    for (map<string, string>::iterator iter = this->header_params.begin(); iter != this->header_params.end(); iter++)
    {
        temp += iter->first + ": " + iter->second + "\r\n";
    }
    this->request_str = temp + "\r\n" + this->body_content;
}

Request::Request(string request_str) {
    this->request_str = request_str;
    istringstream strcin(request_str);
    string temp;
    strcin >> temp;
    this->method = temp;
    strcin >> temp;
    this->path = temp;
    strcin >> temp;
    this->protocol = temp;
    getline(strcin,temp);
    while(getline(strcin,temp)){
        temp.pop_back();
        if(temp.size() == 0) {
            break;
        }
        bool flag = false;
        for(int i=0;i<temp.size();i++){
            if(temp[i]==':') {
                this->header_params[temp.substr(0,i)] = temp.substr(i+2);
                flag = true;
                break;
            }
        }
        if (flag) {} else {
            break;
        }
    }
    while(getline(strcin,temp)){
        this->body_content += temp;
    }
}

string Request::json() {
    string temp = "";
    temp += "{\n";
    temp += "\t\"METHOD\": \"" + this->method + "\"\n";
    temp += "\t\"PATH\": \"" + this->path + "\"\n";
    temp += "\t\"protocol\": \"" + this->protocol + "\"\n";
    for (map<string, string>::iterator iter = this->header_params.begin(); iter != this->header_params.end(); iter++)
    {
        temp += "\t\"" + iter->first + "\": \"" + iter->second + "\"\n";
    }
    temp += "\t\"body_content\": \"" + this->body_content + "\"\n";
    temp += "}\n";
    return temp;
}

string Request::str() {
    return this->request_str;
}

string Request::get_request_url() {
    return "http://" + this->header_params["Host"] + this->path;
}

bool Request::match_path(string path) {
    int index = this->path.find(path);
    return index>=0;
}

void Request::reset_path(string new_path) {
    int index = this->path.find_last_of('/');
    if(index >= 0) {
        this->path = new_path + this->path.substr(index+1);
    } else {
        this->path = new_path + this->path;
    }
    this->reset_request_str();
}

void Request::update_header_params(string key, string value) {
    this->header_params[key] = value;
    this->reset_request_str();
}

string Request::get_header_params(string key) {
    return this->header_params[key];
}

Request::~Request() {}

ostream& operator<<(ostream& out, Request& A) {
    out << A.request_str << endl;
    return out;
}

#endif